package com.asom.player.service;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.provider.MediaStore;

public class MediaLibrary 
{	
	Set<Song>			songs;
	Set<MediaPlaylist> 	playlists;
	Set<Artist>			artists;
	Set<Album>			albums;
	Favorites			favorites;

	MediaPlaylist		currentPlaylist;
			
	ContentResolver		contentResolver;	
	
	<T> void loadItems(Set<T> items, Class<T> _class, Class[] argTypes, Uri uri, String []projection, String selection)
	{
		Cursor		cursor;
		
		try
		{
			cursor = contentResolver.query(
						uri,
						projection, 
						selection, null, null);
			
			while (cursor.moveToNext())
			{
				Object[] params = new String[cursor.getColumnCount()];
				
				for (int iType = 0; iType < argTypes.length; ++ iType)
				{
					if (argTypes[iType].equals(String.class))
						params[iType] = cursor.getString(iType);
					else if (argTypes[iType].equals(int.class))
						params[iType] = cursor.getInt(iType);
				}
				
				try
				{
					Constructor<T> constructor = _class.getConstructor(argTypes);
					
					items.add(constructor.newInstance(params));
				}
				catch (SecurityException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				catch (NoSuchMethodException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				catch (IllegalArgumentException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				catch (InstantiationException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				catch (IllegalAccessException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				catch (InvocationTargetException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		catch(SQLiteException _ex)
		{
			_ex.printStackTrace();
		}
	}
	
	void setSongsAlbumArt()
	{
		Iterator<Song> iterator = null;
		
		iterator = songs.iterator();
		
		while (iterator.hasNext())
		{
			Song song = iterator.next();
			
			song.setAlbumArt(this.loadAlbumArt(song.getAlbum()));
		}
	}
	
	String getAlbumArtByArtist(String _artistName)
	{
		String 		album = "";
		Cursor		cursor;
		
		String[] projection = {
		        MediaStore.Audio.Albums.ALBUM_ART};
		
		String selection = MediaStore.Audio.Albums.ARTIST + " = '" + _artistName + "'";
		
		try
		{
			cursor = contentResolver.query(
						MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
						projection, 
						selection, null, null);
			
			if(cursor.moveToNext())
				album = cursor.getString(0);
		}
		catch(SQLiteException _ex)
		{
			_ex.printStackTrace();
		}
		
		return album;
	}
	
	void setArtistsAlbumArt()
	{
		Iterator<Artist> iterator = null;
		
		iterator = artists.iterator();
		
		while (iterator.hasNext())
		{
			Artist artist = iterator.next();
			
			artist.setAlbumArt(getAlbumArtByArtist(artist.getArtistName()));
		}
	}
	
	String loadAlbumArt(String _album)
	{
		String 		albumArt = "";
		Cursor		cursor;
		
		String[] projection = {
		        MediaStore.Audio.Albums.ALBUM_ART};
		
		String selection = MediaStore.Audio.Albums.ALBUM + " = '" + _album + "'";
		
		try
		{
			cursor = contentResolver.query(
						MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
						projection, 
						selection, null, null);
			
			if(cursor.moveToNext())
				albumArt = cursor.getString(0);
		}
		catch(SQLiteException _ex)
		{
			_ex.printStackTrace();
		}
		
		return albumArt;
	}
	
	void loadSongs()
	{
		songs.clear();
		
		Class[] argTypes = {String.class, String.class, String.class,
				String.class, String.class, String.class,
				String.class};
		
		String[] projection = {
		        MediaStore.Audio.Media.ALBUM,
		        MediaStore.Audio.Media.ALBUM_ID,
		        MediaStore.Audio.Media.ARTIST,
		        MediaStore.Audio.Media.TITLE,
		        MediaStore.Audio.Media.DATA,
		        MediaStore.Audio.Media.DISPLAY_NAME,
		        MediaStore.Audio.Media.DURATION};
		
		String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
		
		this.loadItems(
				songs,
				Song.class, 
				argTypes,
				MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
				projection, 
				selection);
		
		this.setSongsAlbumArt();
		
		if (playlists.size() == 0)
		{
			Iterator<Song> 	itSong; 
			
			itSong = songs.iterator();
			
			while (itSong.hasNext())
				this.getCurrentPlaylist().addSong((Song)itSong.next());
			
			playlists.add(currentPlaylist);
		}
	}
	
	void loadPlaylists()
	{	
		Class[] argTypes = {String.class};
		
		String[] projection = {
				MediaStore.Audio.Playlists.NAME};
		
		this.loadItems(
				playlists,
				MediaPlaylist.class,
				argTypes,
				MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
				projection, null);		
	}
	
	void loadArtists()
	{
		artists.clear();
		
		Class[] argTypes = {String.class, String.class, String.class, String.class};
		
		String[] projection = {
		        MediaStore.Audio.Artists.ARTIST,
		        MediaStore.Audio.Artists.ARTIST_KEY,
		        MediaStore.Audio.Artists.NUMBER_OF_ALBUMS,
		        MediaStore.Audio.Artists.NUMBER_OF_TRACKS};
		
		this.loadItems(
				artists,
				Artist.class, 
				argTypes,
				MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
				projection, 
				null);
		
		this.loadItems(
				artists,
				Artist.class, 
				argTypes,
				MediaStore.Audio.Artists.INTERNAL_CONTENT_URI,
				projection, 
				null);
		
		this.setArtistsAlbumArt();
	}
	
	void loadAlbums()
	{
		albums.clear();
		
		Class[] argTypes = {
				String.class, String.class, String.class, 
				String.class, String.class, String.class,
				String.class};
		
		String[] projection = {
		        MediaStore.Audio.Albums.ALBUM_KEY,
		        MediaStore.Audio.Albums.ALBUM,
		        MediaStore.Audio.Albums.ALBUM_ART,
		        MediaStore.Audio.Albums.ARTIST,
		        MediaStore.Audio.Albums.FIRST_YEAR,
		        MediaStore.Audio.Albums.LAST_YEAR,
		        MediaStore.Audio.Albums.NUMBER_OF_SONGS};
		
		this.loadItems(
				albums,
				Album.class, 
				argTypes,
				MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
				projection, 
				null);
		
		this.loadItems(
				albums,
				Album.class, 
				argTypes,
				MediaStore.Audio.Albums.INTERNAL_CONTENT_URI,
				projection, 
				null);
	}
	
	void load()
	{	
		loadSongs();	
		loadPlaylists();
		loadArtists();
		loadAlbums();
	}
	
	public MediaLibrary(ContentResolver _contentResolver)
	{
		contentResolver = _contentResolver;
		
		songs = new TreeSet<Song>();
		playlists = new TreeSet<MediaPlaylist>();
		artists = new TreeSet<Artist>();
		albums = new TreeSet<Album>();
		favorites = new Favorites();
		
		this.load();
	}
	
	public void setContext(Context _context)
	{
		favorites.setContext(_context);
	}
	
	public MediaPlaylist getCurrentPlaylist()
	{
		if (currentPlaylist == null)
			currentPlaylist = new MediaPlaylist("Recently Added");
		
		return currentPlaylist;
	}
	
	public void setCurrentPlaylist(MediaPlaylist _playlist)
	{
		currentPlaylist = _playlist;
	}

	public void play()
	{
		this.getCurrentPlaylist().play();
	}
	
	public void play(Song _song)
	{
		Iterator<MediaPlaylist> iterator = playlists.iterator(); 
		
		while (iterator.hasNext())
		{
			MediaPlaylist playlist = null;

			playlist = iterator.next();
			
			if (playlist.hasSong(_song))
				this.setCurrentPlaylist(playlist);
			
			this.getCurrentPlaylist().play(_song);
		}
	}
	
	public void pause()
	{
		this.getCurrentPlaylist().pause();
	}
	
	public void stop()
	{
		this.getCurrentPlaylist().stop();
	}
	
	public boolean isPlaying()
	{
		return this.getCurrentPlaylist().isPlaying();
	}
	
	public void favorite()
	{
		if (this.isPlaying())
			favorites.addSong(this.getCurrentPlaylist().getCurrentSong());
	}
	
	public void favorite(Song _song)
	{
		favorites.addSong(_song);
	}
	
	public void next()
	{
		this.getCurrentPlaylist().next();
	}
	
	public void prev()
	{
		this.getCurrentPlaylist().prev();
	}
	
	public void setShuffle(boolean _shuffle)
	{
		this.getCurrentPlaylist().setShuffle(_shuffle);
	}
	
	public boolean getShuffle()
	{
		return this.getCurrentPlaylist().getShuffle();
	}
	
	public void addPlaylist(MediaPlaylist _playlist)
	{
		playlists.add(_playlist);
	}
	
	public void removePlaylist(MediaPlaylist _playlist)
	{
		playlists.remove(_playlist);
	}
	
	public MediaPlaylist[] getPlaylists()
	{
		return playlists.toArray(new MediaPlaylist[playlists.size()]);
	}
	
	public Song[] getSongs()
	{
		return songs.toArray(new Song[songs.size()]);
	}
	
	public Artist[] getArtists()
	{
		return artists.toArray(new Artist[artists.size()]);
	}
	
	public Album[] getAlbums()
	{
		return albums.toArray(new Album[albums.size()]);
	}
	
	public Song[] getFavorites()
	{
		return favorites.getSongs();
	}
	
	public void save()
	{
		favorites.save();
	}
}
